/** ip_config_get.c
 * author: cugfeng@gmail.com
 * date : 20090119
 **/

#include <stdio.h>
#include <error.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/if.h>
#include <net/route.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>

#include "ipconfig.h"

static char *interface = "eth0";

/**
 * return 0 on success, -1 otherwise
 * 通过ioctl方式修改ip地址
 **/
int ip_config_ioctl(const IP *ip)
{
	int                sockfd;
	struct ifreq       ifr;
	struct rtentry     rte;
	struct sockaddr_in *sin;
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		#ifdef _debug_
		perror("create socket error");
		#endif
		return -1;
	}

	// set ip address
	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, interface);
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	sin->sin_family = AF_INET;
	inet_pton(AF_INET, ip->ipaddr, &sin->sin_addr);
	if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0 ) {
		#ifdef _debug_
		perror("SIOCSIFADDR");
		#endif
		close(sockfd);
		return -1;
	}
	
	// set subnet mask
	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, interface);
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	sin->sin_family = AF_INET;
	inet_pton(AF_INET, ip->netmask, &sin->sin_addr);
	if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0 ) {
		#ifdef _debug_
		perror("SIOCSIFNETMASK");
		#endif
		close(sockfd);
		return -1;
	}

	// set gatewayip
	memset(&rte, 0, sizeof(rte));
	rte.rt_flags = (RTF_UP | RTF_GATEWAY);
	sin = (struct sockaddr_in *)&rte.rt_gateway;
	sin->sin_family = AF_INET;
	inet_pton(AF_INET, ip->gateway, &sin->sin_addr);
	sin = (struct sockaddr_in *)&rte.rt_dst;
	sin->sin_family = AF_INET;
	if (ioctl(sockfd, SIOCADDRT, &rte) < 0) {
		#ifdef _debug_
		perror("SIOCADDRT");
		#endif
		close(sockfd);
		return -1;
	}
	
	close(sockfd);
	return 0;
}

/**
 * return 0 on success, -1 otherwise
 * 通过proc方式获取ip地址
 **/
static int ip_get_proc(IP *ip)
{
	FILE *fp;
	char buf[512];
	
	// route
	fp = fopen("/proc/net/route", "r");
	if (fp == NULL) {
		perror("open file /proc/net/route failed");
		return -1;
	}
	while (fgets(buf, sizeof(buf), fp) != NULL) {
		unsigned long dest, gate;
		dest = gate = 0;
		sscanf(buf, "%*s%lx%lx", &dest, &gate);
		if (dest == 0 && gate != 0) {
			inet_ntop(AF_INET, &gate, ip->gateway, 16);
			break;
		}
	}
	fclose(fp);
	
	return 0;
}

/**
 * return 0 on success, -1 otherwise
 * ioctl方式获取ip地址
 **/
int ip_get_ioctl(IP *ip)
{
	int                sockfd;
	struct ifreq       ifr;
	struct rtentry     rte;
	struct sockaddr_in *sin;
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd < 0) {
		perror("create socket error");
		return -1;
	}

	// get ip address
	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, interface);
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	sin->sin_family = AF_INET;
	if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0 ) {
		perror("SIOCGIFADDR");
		close(sockfd);
		return -1;
	}
	inet_ntop(AF_INET, &sin->sin_addr, ip->ipaddr, 16);
	
	// get subnet mask
	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, interface);
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	sin->sin_family = AF_INET;
	if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0 ) {
		perror("SIOCGIFNETMASK");
		close(sockfd);
		return -1;
	}
	inet_ntop(AF_INET, &sin->sin_addr, ip->netmask, 16);
	
	close(sockfd);
	return 0;
}

void print_ip(void)
{
	IP ip;
	memset(&ip, 0, sizeof(ip));
	if (!ip_get_ioctl(&ip) && !ip_get_proc(&ip)) {
		printf("				IP: %s\n", ip.ipaddr);
		printf("				MASK: %s\n", ip.netmask);
		printf("				GW: %s\n", ip.gateway);
	}
	return;
}
